﻿using System;
using System.IO;
using System.Configuration;

namespace SvnPmtHook
{
	public class Program
	{
		private const string MESSAGE_SVNLOOKEXEPATH_MISSING = @"There should be an appSetting key named 'SvnlookExe_Path' with the path and filename to the svnlook executable.  The path is usually, C:\Program Files\CollabNet Subversion Server\svnlook.exe";
		private const string MESSAGE_SVNLOGSERVICEURL_MISSING = "I expected to find the SvnLogService_Url appSetting key and didn't find one, and if it was in there it had no value.";
		private const string MESSAGE_SVNLOOKEXEPATH_NOTFOUND = "I expected to find the svnlook executable here, {0}, that's what's in the config file, but it wasn't there.  Check the path again and make sure it's there.";
		private const string MESSAGE_LOGFILEPATH_MISSING = "You can enable the log file by adding an appSetting key named 'LogFile_Path' and setting it's value to the path and filename of where you want the log file to be written.";
		private const string MESSAGE_LOGMESSAGETEMPLATE_MISSING = "There should be an appSetting key named 'LogMessageTemplate_Path' that has a value that is the full path to a text file containing the format for log messages.";
		private const string MESSAGE_LOGMESSAGETEMPLATE_NOTFOUND = "I expected to find the log message template here '{0}' but I couldn't find it.  Did you put the file somewhere else? Check the path to the template and make sure it's correct and the template file is actually at that location.";


		static void Main(string[] args)
		{
			try
			{
				if (args == null || args.Length != 2)
				{
					ShowHelp();
					return;
				}

				#region verify required settings are present
				string url = ConfigurationManager.AppSettings["SvnLogService_Url"];
				if (String.IsNullOrEmpty(url))
				{
					throw new InvalidOperationException(MESSAGE_SVNLOGSERVICEURL_MISSING);
				}
				string svnlookExePath = ConfigurationManager.AppSettings["SvnlookExe_Path"];
				if (String.IsNullOrEmpty(svnlookExePath))
				{
					throw new InvalidOperationException(MESSAGE_SVNLOOKEXEPATH_MISSING);
				}
				if (!File.Exists(svnlookExePath))
				{
					throw new FileNotFoundException(String.Format(MESSAGE_SVNLOOKEXEPATH_NOTFOUND, svnlookExePath));
				}
				string logMessageTemplatePath = ConfigurationManager.AppSettings["LogMessageTemplate_Path"];
				if (String.IsNullOrEmpty(logMessageTemplatePath))
				{
					throw new InvalidOperationException(MESSAGE_LOGMESSAGETEMPLATE_MISSING);
				}
				if (!File.Exists(logMessageTemplatePath))
				{
					throw new FileNotFoundException(String.Format(MESSAGE_LOGMESSAGETEMPLATE_NOTFOUND, logMessageTemplatePath));
				}
				#endregion
				
				Program program = new Program();
				program.Run(args[0], Convert.ToInt32(args[1]), url, svnlookExePath, logMessageTemplatePath);
				Log("program ended successfully");
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.ToString());
				Log(ex.ToString());
			}
#if (IDE)
			Console.WriteLine("Press <Enter> to exit...");
			Console.ReadLine();
#endif
		}
		private static void Log(string s)
		{
			if (String.IsNullOrEmpty(s))
				return;

			try
			{
				string logfile = ConfigurationManager.AppSettings["LogFile_Path"];
				if (String.IsNullOrEmpty(logfile) || !File.Exists(logfile))
				{
					Console.WriteLine(MESSAGE_LOGFILEPATH_MISSING);
					Console.WriteLine(s);
				}

				Console.WriteLine(s);
				using (StreamWriter file = new StreamWriter(logfile, true))
                {
					file.WriteLine("**************************");
					file.WriteLine(DateTime.Now.ToString());
					file.WriteLine();
					file.WriteLine(s);
					file.WriteLine();
                }
			}
			catch (Exception ex)
			{
				//if we fail at writing the log file, then write out 
				//the error to the console and squish it.
				Console.WriteLine(ex.ToString());
			}
		}
		private static void ShowHelp()
		{
			Console.WriteLine("Usage:");
			Console.WriteLine("SvnPmtHook.exe repo_path rep_rev");
			Console.WriteLine("repo_path = path to the repository");
			Console.WriteLine("eg. /AwishWork/Awish.Common");
			Console.WriteLine("repo_rev = revision that was committed");
			Console.WriteLine("eg. 1344");
			Console.WriteLine("example: SvnPmtHook.exe /AwishWork/Awish.Common 1344");
		}

		public void Run(string repository, int revision, string logServiceUrl, string pathToSvnLookExecutable, string pathToLogMessageTemplate)
		{
			#region contract
			if (String.IsNullOrEmpty(repository))
				throw new ArgumentException("repo is null or empty.", "repository");
			if (String.IsNullOrEmpty(logServiceUrl))
				throw new ArgumentException("url is null or empty.", "logServiceUrl");
			if (String.IsNullOrEmpty(pathToSvnLookExecutable))
				throw new ArgumentException("svnExePath is null or empty.", "pathToSvnLookExecutable");
			#endregion
			
			ISvnLogService logService = new SvnLogService(logServiceUrl);
			ICaptureConsole console = new SilentCaptureConsoleImpl();			
			IParse tokenParser = new TokenParser();
			ISvnLookExecutor svnlookExecutor = new SvnLookExecutor(console, pathToSvnLookExecutable, repository);
			CommitProcessor committer = new CommitProcessor(tokenParser, logService, svnlookExecutor, pathToLogMessageTemplate);
			var response = committer.Commit(repository, revision);
			if (!response.Success)
			{
				Log(response.Message);
			}
		}
	}
}